/*
 * @Author: wuqingchun
 * @Date: 2024-04-29 13:53:01
 * @Description: 
 * @LastEditors: wuqingchun
 * @LastEditTime: 2024-05-07 14:28:02
 */

#include <iostream>

#include "tmp_function.h"

#include <type_traits>

void use_meta_program_library()
{
    std::cout << __FUNCTION__ << std::endl;

    std::cout << "int is reference ? " << std::is_reference<int>::value << std::endl;
    std::cout << "int& is reference ? " << std::is_reference<int&>::value << std::endl;
    std::cout << "int&& is reference ? " << std::is_reference<int&>::value << std::endl;

    
    std::cout << "double is integer ? " << std::is_integral<double>::value << std::endl;
    std::cout << "char is integer ? " << std::is_integral<char>::value << std::endl;
    std::cout << "unsigned char is integer ? " << std::is_integral<unsigned char>::value << std::endl;
    std::cout << "int is integer ? " << std::is_integral<int>::value << std::endl;
    std::cout << "unsigned int is integer ? " << std::is_integral<unsigned int>::value << std::endl;
    std::cout << "short is integer ? " << std::is_integral<short>::value << std::endl;
    std::cout << "unsigned short is integer ? " << std::is_integral<unsigned short>::value << std::endl;
    std::cout << "long is integer ? " << std::is_integral<long>::value << std::endl;
    std::cout << "unsigned long is integer ? " << std::is_integral<unsigned long>::value << std::endl;
}

void use_my_meta_program()
{
    std::cout << __FUNCTION__ << std::endl;

    std::cout << "int is reference ? " << mymeta::is_reference<int>::value << std::endl;
    std::cout << "int& is reference ? " << mymeta::is_reference<int&>::value << std::endl;
    std::cout << "int&& is reference ? " << mymeta::is_reference<int&>::value << std::endl;

    std::cout << "double is integer ? " << mymeta::is_integral<double>::value << std::endl;
    std::cout << "char is integer ? " << mymeta::is_integral<char>::value << std::endl;
    std::cout << "unsigned char is integer ? " << mymeta::is_integral<unsigned char>::value << std::endl;
    std::cout << "int is integer ? " << mymeta::is_integral<int>::value << std::endl;
    std::cout << "unsigned int is integer ? " << mymeta::is_integral<unsigned int>::value << std::endl;
    std::cout << "short is integer ? " << mymeta::is_integral<short>::value << std::endl;
    std::cout << "unsigned short is integer ? " << mymeta::is_integral<unsigned short>::value << std::endl;
    std::cout << "long is integer ? " << mymeta::is_integral<long>::value << std::endl;
    std::cout << "unsigned long is integer ? " << mymeta::is_integral<unsigned long>::value << std::endl;

    std::cout << mymeta::binary<0>::value << std::endl;
    std::cout << mymeta::binary<1>::value << std::endl;
    std::cout << mymeta::binary<10>::value << std::endl;
    std::cout << mymeta::binary<11>::value << std::endl;
    std::cout << mymeta::binary<100>::value << std::endl;
    std::cout << mymeta::binary<101>::value << std::endl;
    std::cout << mymeta::binary<110>::value << std::endl;
    std::cout << mymeta::binary<111>::value << std::endl;

    int var1 = 100;
    mymeta::remove_reference<int>::type var2 = var1;
    mymeta::remove_reference<int&>::type var3 = var1;
    mymeta::remove_reference<int&&>::type var4 = var1;

    int var11 = 100;
    mymeta::type_identity<int>::type var12 = var11;
    // error: ‘var13’ declared as reference but not initialized
    // mymeta::type_identity<int&>::type var13;
    mymeta::type_identity<int&>::type var13 = var11;
    // error: cannot bind rvalue reference of type ‘mymeta::type_identity<int&&>::type {aka int&&}’ to lvalue of type int’
    //mymeta::type_identity<int&&>::type var14 = var11;
    mymeta::type_identity<int&&>::type var14 = 10;

    mymeta::integral_constant<int, 10>::type i;

    std::cout << i << std::endl;
    std::cout << i() << std::endl;

    std::cout << mymeta::is_reference_v2<int>::type::value << std::endl;
    std::cout << mymeta::is_reference_v2<int>::type() << std::endl;
    std::cout << mymeta::is_reference_v2<int>::type()() << std::endl;
}

int main(int argc, char** argv)
{
    use_meta_program_library();

    std::cout << std::endl;

    use_my_meta_program();

    return 0;
}